package com.klm.easymq.metrics;

import io.micrometer.core.instrument.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Easy-MQ 指标收集器
 * 使用 Micrometer 收集各种MQ指标
 */
@Slf4j
@Component
public class EasyMqMetrics {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    // 计数器缓存
    private final ConcurrentHashMap<String, Counter> counters = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Timer> timers = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Gauge> gauges = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, AtomicLong> gaugeValues = new ConcurrentHashMap<>();
    
    // 消息发送计数器
    public void incrementMessageSent(String adapterType, String topic, boolean success) {
        String counterName = "easy_mq_messages_sent_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .tag("result", success ? "success" : "failed")
                .description("Total number of messages sent")
                .register(meterRegistry)
        );
        counter.increment();
    }
    
    // 消息消费计数器
    public void incrementMessageConsumed(String adapterType, String topic, boolean success) {
        String counterName = "easy_mq_messages_consumed_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .tag("result", success ? "success" : "failed")
                .description("Total number of messages consumed")
                .register(meterRegistry)
        );
        counter.increment();
    }
    
    // 消息发送延迟
    public Timer.Sample startMessageSendTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void stopMessageSendTimer(Timer.Sample sample, String adapterType, String topic, boolean success) {
        String timerName = "easy_mq_message_send_duration";
        Timer timer = timers.computeIfAbsent(timerName, name -> 
            Timer.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .tag("result", success ? "success" : "failed")
                .description("Message send duration")
                .register(meterRegistry)
        );
        sample.stop(timer);
    }
    
    // 消息消费延迟
    public Timer.Sample startMessageConsumeTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void stopMessageConsumeTimer(Timer.Sample sample, String adapterType, String topic, boolean success) {
        String timerName = "easy_mq_message_consume_duration";
        Timer timer = timers.computeIfAbsent(timerName, name -> 
            Timer.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .tag("result", success ? "success" : "failed")
                .description("Message consume duration")
                .register(meterRegistry)
        );
        sample.stop(timer);
    }
    
    // 连接状态指标
    public void setConnectionStatus(String adapterType, boolean connected) {
        String gaugeName = "easy_mq_connection_status";
        AtomicLong value = gaugeValues.computeIfAbsent(gaugeName, name -> new AtomicLong(0));
        
        if (!gauges.containsKey(gaugeName)) {
            Gauge gauge = Gauge.builder(gaugeName, value, AtomicLong::get)
                .tag("adapter", adapterType)
                .description("MQ connection status (1=connected, 0=disconnected)")
                .register(meterRegistry);
            gauges.put(gaugeName, gauge);
        }
        
        value.set(connected ? 1 : 0);
    }
    
    // 队列大小指标
    public void setQueueSize(String adapterType, String topic, long size) {
        String gaugeName = "easy_mq_queue_size";
        String key = adapterType + "_" + topic;
        AtomicLong value = gaugeValues.computeIfAbsent(key, name -> new AtomicLong(0));
        
        if (!gauges.containsKey(key)) {
            Gauge gauge = Gauge.builder(gaugeName, value, AtomicLong::get)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .description("MQ queue size")
                .register(meterRegistry);
            gauges.put(key, gauge);
        }
        
        value.set(size);
    }
    
    // 错误计数器
    public void incrementError(String adapterType, String errorType) {
        String counterName = "easy_mq_errors_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("error_type", errorType)
                .description("Total number of errors")
                .register(meterRegistry)
        );
        counter.increment();
    }
    
    // 重试计数器
    public void incrementRetry(String adapterType, String topic) {
        String counterName = "easy_mq_retries_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .description("Total number of retries")
                .register(meterRegistry)
        );
        counter.increment();
    }
    
    // 幂等跳过计数器
    public void incrementIdempotentSkip(String adapterType, String topic) {
        String counterName = "easy_mq_idempotent_skips_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .description("Total number of idempotent skips")
                .register(meterRegistry)
        );
        counter.increment();
    }
    
    // 批量发送计数器
    public void recordBatchSend(String adapterType, String topic, int batchSize, boolean success) {
        String counterName = "easy_mq_batch_sends_total";
        Counter counter = counters.computeIfAbsent(counterName, name -> 
            Counter.builder(name)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .tag("result", success ? "success" : "failed")
                .description("Total number of batch sends")
                .register(meterRegistry)
        );
        counter.increment();
        
        // 记录批量大小
        String gaugeName = "easy_mq_batch_size";
        AtomicLong value = gaugeValues.computeIfAbsent(gaugeName, name -> new AtomicLong(0));
        
        if (!gauges.containsKey(gaugeName)) {
            Gauge gauge = Gauge.builder(gaugeName, value, AtomicLong::get)
                .tag("adapter", adapterType)
                .tag("topic", topic)
                .description("Batch size")
                .register(meterRegistry);
            gauges.put(gaugeName, gauge);
        }
        
        value.set(batchSize);
    }
    
    // 获取指标统计信息
    public Map<String, Object> getMetricsSummary() {
        Map<String, Object> summary = new HashMap<>();
        
        // 统计计数器
        Map<String, Long> counterStats = new HashMap<>();
        for (Map.Entry<String, Counter> entry : counters.entrySet()) {
            counterStats.put(entry.getKey(), (long) entry.getValue().count());
        }
        summary.put("counters", counterStats);
        
        // 统计计时器
        Map<String, Object> timerStats = new HashMap<>();
        for (Map.Entry<String, Timer> entry : timers.entrySet()) {
            Timer timer = entry.getValue();
            Map<String, Object> stats = new HashMap<>();
            stats.put("count", timer.count());
            stats.put("totalTime", timer.totalTime(TimeUnit.MILLISECONDS));
            stats.put("mean", timer.mean(TimeUnit.MILLISECONDS));
            stats.put("max", timer.max(TimeUnit.MILLISECONDS));
            timerStats.put(entry.getKey(), stats);
        }
        summary.put("timers", timerStats);
        
        // 统计仪表
        Map<String, Long> gaugeStats = new HashMap<>();
        for (Map.Entry<String, AtomicLong> entry : gaugeValues.entrySet()) {
            gaugeStats.put(entry.getKey(), entry.getValue().get());
        }
        summary.put("gauges", gaugeStats);
        
        return summary;
    }
} 